#include <iostream>
#include <string>
#include <sstream>//antes strstream
#include <vector>
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>

typedef std::vector<std::string>      VStrRenglon;
typedef std::vector<VStrRenglon> VStrMatriz; //vector < vector <string> >

#define DEFAULT_NULL "- -"

class MySQLWrapper {
private:

  unsigned int _iPuerto;
  std::string _strServidor, _strBase, _strUsuario, _strPassword;

  mutable MYSQL ConexionAMySQL;
  MYSQL_ROW Renglon;
  MYSQL_RES * RespuestaDeMySQL;

  int NumeroColumnas;
  int NumeroRenglones;

  int traerRenglon();
  int barrerResultado( VStrMatriz & VStrResultado );
  void liberarResultado();

  int getError ( );                                                                                                                                                                 // void CreaQuery ( char *CualPlantilla, char *CualesValores[], char *CualQuery );

public:

  MySQLWrapper ( void );
  ~MySQLWrapper ();

  int ejecutarConexion ( unsigned int iPuerto, std::string strServidor, std::string strBaseDeDatos, std::string strUsuario, std::string strPassword );
  void ejecutarDesconexion();

  int insertarDatos( std::string strConsulta );
  int adquirirDatos ( std::string strConsulta, VStrMatriz & VStrResultado );
};

int insertarDatos ( MySQLWrapper & base, std::string strConsulta );
int adquirirDatos ( MySQLWrapper & base, std::string strConsulta, VStrMatriz & VStrResultado );
//------------------------------------------------------------------------------













MySQLWrapper::MySQLWrapper() {}
MySQLWrapper::~MySQLWrapper() {}
//------------------------------------------------------------------------------











int MySQLWrapper::ejecutarConexion ( unsigned int iPuerto, std::string strServidor, std::string strBaseDeDatos, std::string strUsuario, std::string strPassword ) {
  _iPuerto      = iPuerto;
  _strServidor  = strServidor;
  _strBase      = strBaseDeDatos;
  _strUsuario   = strUsuario;
  _strPassword  = strPassword;

  mysql_init( &ConexionAMySQL );
  if ( NULL == &ConexionAMySQL ) { return -1; }
  std::cout << "\nconexion a MySQL inicializada\n" << std::endl;
  if ( !mysql_real_connect( &ConexionAMySQL, _strServidor.c_str(), _strUsuario.c_str(), _strPassword.c_str(), _strBase.c_str(), iPuerto, NULL, 0) ) { return -2; }
  std::cout << "\nconexion a MySQL con usuario y password dados exitosa\n" << std::endl;
  if ( !mysql_set_character_set( &ConexionAMySQL, "latin1" ) ) {} else { return -3; }
  return 0;
}
//------------------------------------------------------------------------------











void MySQLWrapper::ejecutarDesconexion () {
  mysql_close( &ConexionAMySQL );
}
//------------------------------------------------------------------------------











int MySQLWrapper::insertarDatos ( std::string strConsulta ) {
  if ( mysql_query( &ConexionAMySQL, strConsulta.c_str() ) ) {
    return -1;
  } else {
    return mysql_field_count(&ConexionAMySQL);
  }
}
//------------------------------------------------------------------------------











int MySQLWrapper::adquirirDatos ( std::string strConsulta, VStrMatriz & VStrResultado ) {
  if ( mysql_query( &ConexionAMySQL, strConsulta.c_str() ) ) {                                                                                                                                         //    int iCodigoDeError = getError( "Error de MYSQL" ); if ( ER_TABLEACCESS_DENIED_ERROR == iCodigoDeError || ER_NO_SUCH_TABLE == iCodigoDeError ) { return 0; }
    return -1;
  } else {
    RespuestaDeMySQL = mysql_use_result( &ConexionAMySQL );
    NumeroColumnas = ( RespuestaDeMySQL ) ? mysql_num_fields( RespuestaDeMySQL ) : 0;
    NumeroRenglones = barrerResultado( VStrResultado );
    liberarResultado();
    return NumeroRenglones;
  }
}
//------------------------------------------------------------------------------











int MySQLWrapper::barrerResultado( VStrMatriz & VStrResultado ) {
  VStrResultado.clear();
  int iRen = 0;
  while( -1 != traerRenglon() ) {
    VStrResultado.resize( iRen+1 );
    VStrResultado[iRen].resize( NumeroColumnas );
    for ( int iCol = 0; iCol < NumeroColumnas ; ++iCol ) {
      VStrResultado[iRen][iCol] = ( Renglon[iCol] ) ? Renglon[iCol] : DEFAULT_NULL;
    }
    iRen++;
  }
  return iRen;
}
//------------------------------------------------------------------------------











void MySQLWrapper::liberarResultado () {
  mysql_free_result( RespuestaDeMySQL );
}
//------------------------------------------------------------------------------











int MySQLWrapper::traerRenglon () {
  Renglon = mysql_fetch_row(RespuestaDeMySQL);
  if ( NULL == Renglon ) { return -1; }
  //for ( int iCol=0; iCol < NumeroColumnas; ++iCol ) { if (!Renglon[iCol] || std::string(Renglon[iCol]) == std::string("")) { Renglon[iCol]=DEFAULT_NULL; } }
  return 0;
}
//------------------------------------------------------------------------------











int MySQLWrapper::getError () {
  if ( NULL != &ConexionAMySQL ) {
    return mysql_errno(&ConexionAMySQL);
  }
  return 0;
}
//------------------------------------------------------------------------------











int insertarDatos ( MySQLWrapper & base, std::string strConsulta ) {
  return base.insertarDatos( strConsulta );
}
//------------------------------------------------------------------------------











int adquirirDatos ( MySQLWrapper & base, std::string strConsulta, VStrMatriz & VStrResultado ) {
  return base.adquirirDatos( strConsulta, VStrResultado );
}
//------------------------------------------------------------------------------













int ejecutarSolicitudAMySQL ( VStrMatriz & VMatriz ) {
  std::string strConexionBDDireccion = "localhost"   ;
  std::string strConexionBDUsuario   = "root"        ;
  std::string strConexionBDPasswd    = "xxx"         ;
  std::string strConexionBDEsquema   = "information_schema";
  MySQLWrapper             Base                      ;

  if ( Base.ejecutarConexion( 0, strConexionBDDireccion, strConexionBDEsquema, strConexionBDUsuario, strConexionBDPasswd ) < 0) { return -1; }
  std::cout << "\nconexion a MySQL establecida\n" << std::endl;


  std::string strQuery = "SHOW DATABASES;";
  if ( adquirirDatos( Base, strQuery, VMatriz ) < 0 ) { return -2; }
  std::cout << "\ndatos en memoria\n" << std::endl;
  Base.ejecutarDesconexion();
  std::cout << "\ndesconexion de MySQL exitosa\n" << std::endl;
  return 0;
}
//------------------------------------------------------------------------------













void ejecutarEnlaceADatos () {
  std::vector < std::vector <std::string> >  VMatriz;

  std::stringstream sstrResultado;

  std::cout << "\ninicia secuencia de conexion a MySQL\n" << std::endl;
  if( 0 > ejecutarSolicitudAMySQL ( VMatriz ) ) { return; }
  std::cout << "\ndistribuyendo datos en estructuras especificadas\n" << std::endl;

  for (unsigned int Ii = 0; Ii < VMatriz.size(); Ii++) {
    if (Ii > 0 ) { sstrResultado << "\n"; }
    for (unsigned int Ij = 0; Ij < VMatriz[Ii].size(); Ij++) {
        if (Ij > 0 ) { sstrResultado << ", "; }
        sstrResultado << VMatriz[Ii][Ij];
    }
  }
  std::cout << sstrResultado.str() << std::endl;
}
//------------------------------------------------------------------------------













int main(void) {
    ejecutarEnlaceADatos();
    return 0;
}

